home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / editors / stevie3a.6 < prev   
Text File  |  1989-03-15  |  36KB  |  1,805 lines

  1. Path: xanth!ukma!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i045:  stevie - vi-like text editor v35a, Part06/06
  5. Message-ID: <12218@swan.ulowell.edu>
  6. Date: 15 Mar 89 15:13:40 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1794
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: grwalter@watcgl.waterloo.edu (Fred Walter)
  12. Posting-number: Volume 89, Issue 45
  13. Archive-name: editors/stevie35a.6
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    normal.c
  23. # This archive created: Tue Mar 14 14:42:34 1989
  24. cat << \SHAR_EOF > normal.c
  25. /*
  26.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  27.  *
  28.  * Code Contributions By : Tim Thompson           twitch!tjt
  29.  *                         Tony Andrews           onecom!wldrdg!tony 
  30.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  31.  */
  32.  
  33. /*
  34.  * This file contains the main routine for processing characters in command
  35.  * mode as well as routines for handling the operators. 
  36.  */
  37.  
  38. #include "stevie.h"
  39.  
  40. static void
  41. doshift(), dodelete(), doput(), dochange();
  42. static void
  43.                 startinsert();
  44. static          bool_t
  45.                 dojoin();
  46. static          bool_t
  47.                 doyank();
  48.  
  49. /*
  50.  * Macro evaluates true if char 'c' is a valid identifier character 
  51.  */
  52. #define    IDCHAR(c)    (isalpha(c) || isdigit(c) || (c) == '_')
  53.  
  54. /*
  55.  * Operators 
  56.  */
  57. #define    NOP    0        /* no pending operation */
  58. #define    DELETE    1
  59. #define    YANK    2
  60. #define    CHANGE    3
  61. #define    LSHIFT    4
  62. #define    RSHIFT    5
  63.  
  64. #define    CLEAROP    (operator = NOP)/* clear any pending operator */
  65.  
  66. static int      operator = NOP;    /* current pending operator */
  67.  
  68. /*
  69.  * When a cursor motion command is made, it is marked as being a character or
  70.  * line oriented motion. Then, if an operator is in effect, the operation
  71.  * becomes character or line oriented accordingly. 
  72.  *
  73.  * Character motions are marked as being inclusive or not. Most char. motions
  74.  * are inclusive, but some (e.g. 'w') are not. 
  75.  *
  76.  * Generally speaking, every command in normal() should either clear any pending
  77.  * operator (with CLEAROP), or set the motion type variable. 
  78.  */
  79.  
  80. /*
  81.  * Motion types 
  82.  */
  83. #define    MBAD    (-1)        /* 'bad' motion type marks unusable yank buf */
  84. #define    MCHAR    0
  85. #define    MLINE    1
  86.  
  87. static int      mtype;        /* type of the current cursor motion */
  88. static bool_t   mincl;        /* true if char motion is inclusive */
  89. static int      ybtype = MBAD;
  90. static int      ybcrossline = FALSE;
  91.  
  92. static LPtr     startop;    /* cursor pos. at start of operator */
  93.  
  94. /*
  95.  * Operators can have counts either before the operator, or between the
  96.  * operator and the following cursor motion as in: 
  97.  *
  98.  * d3w or 3dw 
  99.  *
  100.  * If a count is given before the operator, it is saved in opnum. If normal() is
  101.  * called with a pending operator, the count in opnum (if present) overrides
  102.  * any count that came later. 
  103.  */
  104. static int      opnum = 0;
  105.  
  106. #define    DEFAULT1(x)    (((x) == 0) ? 1 : (x))
  107.  
  108. /*
  109.  * normal 
  110.  *
  111.  * Execute a command in normal mode. 
  112.  */
  113.  
  114. void
  115. normal(c)
  116.     char            c;
  117. {
  118.     char           *p;
  119.     int             n;
  120.     int             nn;
  121.     bool_t          flag = FALSE;
  122.     int             type = 0;    /* used in some operations to modify type */
  123.     int             dir = FORWARD;    /* search direction */
  124.     char            nchar = NUL;
  125.     bool_t          finish_op;
  126.     LPtr            temp_Curschar;
  127.  
  128.     last_command = NUL;
  129.     /*
  130.      * If there is an operator pending, then the command we take this time
  131.      * will terminate it. Finish_op tells us to finish the operation before
  132.      * returning this time (unless the operation was cancelled). 
  133.      */
  134.     finish_op = (operator != NOP);
  135.  
  136.     /*
  137.      * If we're in the middle of an operator AND we had a count before the
  138.      * operator, then that count overrides the current value of Prenum. What
  139.      * this means effectively, is that commands like "3dw" get turned into
  140.      * "d3w" which makes things fall into place pretty neatly. 
  141.      */
  142.     if (finish_op) {
  143.     if (opnum != 0)
  144.         Prenum = opnum;
  145.     } else
  146.     opnum = 0;
  147.  
  148.     switch (c) {
  149.  
  150.       case K_HELP:
  151.     CLEAROP;
  152.     if (help()) {
  153.         screenclear();
  154.         updateNextscreen(NOT_VALID);
  155.     }
  156.     break;
  157.  
  158.       case CTRL('L'):
  159.     CLEAROP;
  160.     screenclear();
  161.     updateNextscreen(NOT_VALID);
  162.     break;
  163.  
  164.       case CTRL('D'):
  165.     CLEAROP;
  166.     if (Prenum)
  167.         P(P_SS) = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
  168.     scrollup((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  169.     onedown((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  170.     updateNextscreen(VALID);
  171.     break;
  172.  
  173.       case CTRL('U'):
  174.     CLEAROP;
  175.     if (Prenum)
  176.         P(P_SS) = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
  177.     scrolldown((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  178.     oneup((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  179.     updateNextscreen(VALID);
  180.     break;
  181.  
  182.       case CTRL('F'):
  183.     CLEAROP;
  184.     if (nextline(Topchar) == NULL) {
  185.         beep();
  186.         break;
  187.     }
  188.     screenclear();
  189.     Prenum = DEFAULT1(Prenum);
  190.     while (Prenum > 0) {
  191.         *Curschar = *prevline(Botchar);
  192.         *Topchar = *Curschar;
  193.         Topchar->index = 0;
  194.         updateNextscreen(VALID);
  195.         Prenum--;
  196.     }
  197.     beginline(TRUE);
  198.     break;
  199.  
  200.       case CTRL('B'):
  201.     CLEAROP;
  202.     if (prevline(Topchar) == NULL) {
  203.         beep();
  204.         break;
  205.     }
  206.     screenclear();
  207.     Prenum = DEFAULT1(Prenum);
  208.     while (Prenum > 0) {
  209.         *Curschar = *Topchar;
  210.         n = Rows - 1;
  211.         {
  212.         LPtr           *lp = Curschar;
  213.         int             l = 0;
  214.  
  215.         while ((l < n) && (lp != NULL)) {
  216.             l += plines(lp);
  217.             *Topchar = *lp;
  218.             lp = prevline(lp);
  219.         }
  220.         }
  221.         Topchar->index = 0;
  222.         Prenum--;
  223.     }
  224.     beginline(TRUE);
  225.     updateNextscreen(VALID);
  226.     break;
  227.  
  228.       case CTRL('E'):
  229.     CLEAROP;
  230.     scrollup(DEFAULT1(Prenum));
  231.     updateNextscreen(VALID);
  232.     break;
  233.  
  234.       case CTRL('Y'):
  235.     CLEAROP;
  236.     scrolldown(DEFAULT1(Prenum));
  237.     updateNextscreen(VALID);
  238.     break;
  239.  
  240.       case 'z':
  241.     CLEAROP;
  242.     switch (vgetc()) {
  243.       case NL:        /* put Curschar at top of screen */
  244.       case CR:
  245.         *Topchar = *Curschar;
  246.         Topchar->index = 0;
  247.         updateNextscreen(VALID);
  248.         break;
  249.  
  250.       case '.':        /* put Curschar in middle of screen */
  251.         n = Rows / 2;
  252.         goto dozcmd;
  253.  
  254.       case '-':        /* put Curschar at bottom of screen */
  255.         n = Rows - 1;
  256.         /* FALLTHROUGH */
  257.  
  258.     dozcmd:
  259.         {
  260.         register LPtr  *lp = Curschar;
  261.         register int    l = 0;
  262.  
  263.         while ((l < n) && (lp != NULL)) {
  264.             l += plines(lp);
  265.             *Topchar = *lp;
  266.             lp = prevline(lp);
  267.         }
  268.         }
  269.         Topchar->index = 0;
  270.         updateNextscreen(VALID);
  271.         break;
  272.  
  273.       default:
  274.         beep();
  275.     }
  276.     break;
  277.  
  278.       case CTRL('G'):
  279.     CLEAROP;
  280.     fileinfo();
  281.     break;
  282.  
  283.       case 'G':
  284.     mtype = MLINE;
  285.     *Curschar = *gotoline(Prenum);
  286.     if (!UndoInProgress)
  287.         beginline(TRUE);
  288.     break;
  289.  
  290.       case 'H':
  291.     mtype = MLINE;
  292.     *Curschar = *Topchar;
  293.     for (n = Prenum; n && onedown(1); n--);
  294.     beginline(TRUE);
  295.     break;
  296.  
  297.       case 'M':
  298.     mtype = MLINE;
  299.     *Curschar = *Topchar;
  300.     for (n = 0; n < Rows / 2 && onedown(1); n++);
  301.     beginline(TRUE);
  302.     break;
  303.  
  304.       case 'L':
  305.     mtype = MLINE;
  306.     *Curschar = *prevline(Botchar);
  307.     for (n = Prenum; n && oneup(1); n--);
  308.     beginline(TRUE);
  309.     break;
  310.  
  311.       case 'l':
  312.       case K_RARROW:
  313.       case ' ':
  314.     mtype = MCHAR;
  315.     mincl = FALSE;
  316.     n = DEFAULT1(Prenum);
  317.     while (n--) {
  318.         if (!oneright()) {
  319.         if (operator != DELETE && operator != CHANGE) {
  320.             beep();
  321.         } else {
  322.             if (lineempty(Curschar)) {
  323.             CLEAROP;
  324.             beep();
  325.             } else {
  326.             mincl = TRUE;
  327.             }
  328.         }
  329.         break;
  330.         }
  331.     }
  332.     set_want_col = TRUE;
  333.     break;
  334.  
  335.       case 'h':
  336.       case K_LARROW:
  337.       case CTRL('H'):
  338.     mtype = MCHAR;
  339.     mincl = FALSE;
  340.     Prenum = DEFAULT1(Prenum);
  341.     n = Prenum;
  342.     while (n--) {
  343.         if (!oneleft()) {
  344.         if (operator != DELETE && operator != CHANGE) {
  345.             beep();
  346.         } else if (Prenum == 1) {
  347.             CLEAROP;
  348.             beep();
  349.         }
  350.         break;
  351.         }
  352.     }
  353.     set_want_col = TRUE;
  354.     break;
  355.  
  356.       case '-':
  357.     flag = TRUE;
  358.     /* FALLTHROUGH */
  359.  
  360.       case 'k':
  361.       case K_UARROW:
  362.       case CTRL('P'):
  363.     mtype = MLINE;
  364.     if (!oneup(DEFAULT1(Prenum))) {
  365.         CLEAROP;
  366.         beep();
  367.     } else if (flag)
  368.         beginline(TRUE);
  369.     break;
  370.  
  371.       case '+':
  372.       case CR:
  373.       case NL:
  374.     flag = TRUE;
  375.     /* FALLTHROUGH */
  376.  
  377.       case 'j':
  378.       case K_DARROW:
  379.       case CTRL('N'):
  380.     mtype = MLINE;
  381.     if (!onedown(DEFAULT1(Prenum))) {
  382.         CLEAROP;
  383.         beep();
  384.     } else if (flag)
  385.         beginline(TRUE);
  386.     break;
  387.  
  388.     /*
  389.      * This is a strange motion command that helps make operators more
  390.      * logical. It is actually implemented, but not documented in the
  391.      * real 'vi'. This motion command actually refers to "the current
  392.      * line". Commands like "dd" and "yy" are really an alternate form of
  393.      * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  394.      * lines. 
  395.      */
  396.       case '_':
  397. lineop:
  398.     mtype = MLINE;
  399.     if (!onedown(DEFAULT1(Prenum) - 1)) {
  400.         CLEAROP;
  401.         beep();
  402.     } else
  403.         beginline(TRUE);
  404.     break;
  405.  
  406.       case '|':
  407.     mtype = MCHAR;
  408.     mincl = TRUE;
  409.     beginline(FALSE);
  410.     if (Prenum > 0)
  411.         *Curschar = *coladvance(Curschar, Prenum - 1);
  412.     Curswant = Prenum - 1;
  413.     break;
  414.  
  415.       case CTRL(']'):        /* :ta to current identifier */
  416.     CLEAROP;
  417.     {
  418.         char            ch;
  419.         LPtr            save;
  420.  
  421.         save = *Curschar;
  422.         /*
  423.          * First back up to start of identifier. This doesn't match the
  424.          * real vi but I like it a little better and it shouldn't bother
  425.          * anyone. 
  426.          */
  427.         ch = gchar(Curschar);
  428.         while (IDCHAR(ch)) {
  429.         if (!oneleft())
  430.             break;
  431.         ch = gchar(Curschar);
  432.         }
  433.         if (!IDCHAR(ch))
  434.         oneright();
  435.  
  436.         stuffReadbuff(":ta ");
  437.         /*
  438.          * Now grab the chars in the identifier 
  439.          */
  440.         ch = gchar(Curschar);
  441.         while (IDCHAR(ch)) {
  442.         stuffReadbuff(mkstr(ch));
  443.         if (!oneright())
  444.             break;
  445.         ch = gchar(Curschar);
  446.         }
  447.         stuffReadbuff("\n");
  448.  
  449.         *Curschar = save;    /* restore, in case of error */
  450.     }
  451.     break;
  452.  
  453.       case '%':
  454.     mtype = MCHAR;
  455.     mincl = TRUE;
  456.     {
  457.         LPtr           *pos;
  458.  
  459.         if ((pos = showmatch()) == NULL) {
  460.         CLEAROP;
  461.         beep();
  462.         } else {
  463.         setpcmark();
  464.         *Curschar = *pos;
  465.         set_want_col = TRUE;
  466.         }
  467.     }
  468.     break;
  469.  
  470.     /*
  471.      * Word Motions 
  472.      */
  473.  
  474.       case 'B':
  475.     type = 1;
  476.     /* FALLTHROUGH */
  477.  
  478.       case 'b':
  479.     mtype = MCHAR;
  480.     mincl = FALSE;
  481.     set_want_col = TRUE;
  482.     for (n = DEFAULT1(Prenum); n > 0; n--) {
  483.         LPtr           *pos;
  484.  
  485.         if ((Curschar->linep->prev == Filetop->linep)
  486.         && (Curschar->index == 0)) {
  487.         CLEAROP;
  488.         beep();
  489.         break;
  490.         }
  491.         pos = bck_word(Curschar, type);
  492.         if (pos == NULL) {
  493.         CLEAROP;
  494.         beep();
  495.         *Curschar = *gotoline(1);    /* goto top of file */
  496.         } else
  497.         *Curschar = *pos;
  498.     }
  499.     break;
  500.  
  501.       case 'W':
  502.     type = 1;
  503.     /* FALLTHROUGH */
  504.  
  505.       case 'w':
  506.     /*
  507.      * This is a little strange. To match what the real vi does, we
  508.      * effectively map 'cw' to 'ce', and 'cW' to 'cE'. This seems
  509.      * impolite at first, but it's really more what we mean when we say
  510.      * 'cw'. 
  511.      */
  512.     if (operator == CHANGE)
  513.         goto doecmd;
  514.  
  515.     mtype = MCHAR;
  516.     mincl = FALSE;
  517.     set_want_col = TRUE;
  518.     for (n = DEFAULT1(Prenum); n > 0; n--) {
  519.         LPtr           *pos;
  520.  
  521.         if ((pos = fwd_word(Curschar, type)) == NULL) {
  522.         CLEAROP;
  523.         beep();
  524.         break;
  525.         } else
  526.         *Curschar = *pos;
  527.     }
  528.     break;
  529.  
  530.       case 'E':
  531.     type = 1;
  532.     /* FALLTHROUGH */
  533.  
  534.       case 'e':
  535. doecmd:
  536.     mtype = MCHAR;
  537.     mincl = TRUE;
  538.     set_want_col = TRUE;
  539.     for (n = DEFAULT1(Prenum); n > 0; n--) {
  540.         LPtr           *pos;
  541.  
  542.         if ((pos = end_word(Curschar, type)) == NULL) {
  543.         CLEAROP;
  544.         beep();
  545.         break;
  546.         } else
  547.         *Curschar = *pos;
  548.     }
  549.     break;
  550.  
  551.       case '$':
  552.     mtype = MCHAR;
  553.     mincl = TRUE;
  554.     while (oneright());
  555.     Curswant = 999;        /* so we stay at the end */
  556.     break;
  557.  
  558.       case '^':
  559.     flag = TRUE;
  560.     /* FALLTHROUGH */
  561.  
  562.       case '0':
  563.     mtype = MCHAR;
  564.     mincl = TRUE;
  565.     beginline(flag);
  566.     break;
  567.  
  568.       case 'A':
  569.     set_want_col = TRUE;
  570.     while (oneright());
  571.     ResetBuffers();
  572.     AppendToRedobuff("A");
  573.     goto doAPPENDcmd;
  574.  
  575.       case 'a':
  576.     ResetBuffers();
  577.     AppendToRedobuff("a");
  578.  
  579. doAPPENDcmd:
  580.     CLEAROP;
  581.     /* Works just like an 'i'nsert on the next character. */
  582.     n = RowNumber(Curschar);
  583.     AppendPositionToUndoUndobuff(Curschar->index, n);
  584.     AppendToUndoUndobuff("a");
  585.  
  586.     if (!lineempty(Curschar))
  587.         inc(Curschar);
  588.  
  589.     n = RowNumber(Curschar);
  590.     AppendPositionToUndobuff(Curschar->index, n);
  591.  
  592.     startinsert(FALSE);
  593.     break;
  594.  
  595.       case 'I':
  596.     beginline(TRUE);
  597.     ResetBuffers();
  598.     AppendToRedobuff("I");
  599.     goto doINSERTcmd;
  600.     /* FALLTHROUGH */
  601.  
  602.       case 'i':
  603.       case K_INSERT:
  604.     ResetBuffers();
  605.     AppendToRedobuff("i");
  606.  
  607. doINSERTcmd:
  608.     CLEAROP;
  609.  
  610.     n = RowNumber(Curschar);
  611.     AppendPositionToUndobuff(Curschar->index, n);
  612.     AppendPositionToUndoUndobuff(Curschar->index, n);
  613.     AppendToUndoUndobuff("i");
  614.  
  615.     startinsert(FALSE);
  616.     break;
  617.  
  618.       case 'o':
  619.     CLEAROP;
  620.     ResetBuffers();
  621.  
  622.     n = RowNumber(Curschar);
  623.     AppendToRedobuff("o");
  624.     AppendPositionToUndobuff(Curschar->index, n);
  625.     AppendPositionToUndoUndobuff(Curschar->index, n);
  626.     AppendToUndoUndobuff("o");
  627.  
  628.     if (OpenForward(!RedrawingDisabled))
  629.         startinsert(TRUE);
  630.  
  631.     last_command = 'o';
  632.     break;
  633.  
  634.       case 'O':
  635.     CLEAROP;
  636.     ResetBuffers();
  637.  
  638.     n = RowNumber(Curschar);
  639.     AppendToRedobuff("O");
  640.     AppendPositionToUndobuff(Curschar->index, n);
  641.     AppendPositionToUndoUndobuff(Curschar->index, n);
  642.     AppendToUndoUndobuff("O");
  643.  
  644.     if (OpenBackward(!RedrawingDisabled))
  645.         startinsert(TRUE);
  646.  
  647.     last_command = 'O';
  648.     break;
  649.  
  650.       case 'd':
  651.     if (operator == DELETE)    /* handle 'dd' */
  652.         goto lineop;
  653.     if (Prenum != 0)
  654.         opnum = Prenum;
  655.     startop = *Curschar;
  656.     operator = DELETE;
  657.     break;
  658.  
  659.     /*
  660.      * Some convenient abbreviations... 
  661.      */
  662.  
  663.       case 'x':
  664.     if (Prenum)
  665.         stuffnumReadbuff(Prenum);
  666.     stuffReadbuff("dl");
  667.     break;
  668.  
  669.       case 'X':
  670.     if (Prenum)
  671.         stuffnumReadbuff(Prenum);
  672.     stuffReadbuff("dh");
  673.     break;
  674.  
  675.       case 'D':
  676.     stuffReadbuff("d$");
  677.     break;
  678.  
  679.       case 'Y':
  680.     if (Prenum)
  681.         stuffnumReadbuff(Prenum);
  682.     stuffReadbuff("yy");
  683.     break;
  684.  
  685.       case 'C':
  686.     stuffReadbuff("c$");
  687.     break;
  688.  
  689.       case 'c':
  690.     if (operator == CHANGE) {    /* handle 'cc' */
  691.         CLEAROP;
  692.         stuffReadbuff("0c$");
  693.         break;
  694.     }
  695.     if (Prenum != 0)
  696.         opnum = Prenum;
  697.     startop = *Curschar;
  698.     operator = CHANGE;
  699.     break;
  700.  
  701.       case 'y':
  702.     if (operator == YANK)    /* handle 'yy' */
  703.         goto lineop;
  704.     if (Prenum != 0)
  705.         opnum = Prenum;
  706.     startop = *Curschar;
  707.     operator = YANK;
  708.     break;
  709.  
  710.       case ENABLE_REDRAWING:
  711.     RedrawingDisabled = FALSE;
  712.     updateNextscreen(NOT_VALID);
  713.     break;
  714.  
  715.       case 'p':
  716.     if (Yankbuffptr != NULL) {
  717.         doput(FORWARD);
  718.  
  719.         stuffReadbuff(ENABLE_REDRAWING_STR);
  720.         RedrawingDisabled = TRUE;
  721.     } else
  722.         beep();
  723.     break;
  724.  
  725.       case 'P':
  726.     if (Yankbuffptr != NULL) {
  727.         doput(BACKWARD);
  728.  
  729.         stuffReadbuff(ENABLE_REDRAWING_STR);
  730.         RedrawingDisabled = TRUE;
  731.     } else
  732.         beep();
  733.     break;
  734.  
  735.       case '>':
  736.     if (operator == RSHIFT)    /* handle >> */
  737.         goto lineop;
  738.     if (operator == LSHIFT) {
  739.         CLEAROP;
  740.         beep();
  741.         break;
  742.     }
  743.     if (Prenum != 0)
  744.         opnum = Prenum;
  745.     startop = *Curschar;    /* save current position */
  746.     operator = RSHIFT;
  747.     break;
  748.  
  749.       case '<':
  750.     if (operator == LSHIFT)    /* handle << */
  751.         goto lineop;
  752.     if (operator == RSHIFT) {
  753.         CLEAROP;
  754.         beep();
  755.         break;
  756.     }
  757.     if (Prenum != 0)
  758.         opnum = Prenum;
  759.     startop = *Curschar;    /* save current position */
  760.     operator = LSHIFT;
  761.     break;
  762.  
  763.       case 's':        /* substitute characters */
  764.     if (Prenum)
  765.         stuffnumReadbuff(Prenum);
  766.     stuffReadbuff("cl");
  767.     break;
  768.  
  769.       case '?':
  770.       case '/':
  771.       case ':':
  772.     CLEAROP;
  773.     readcmdline(c, (char *) NULL);
  774.     break;
  775.  
  776.       case 'n':
  777.     mtype = MCHAR;
  778.     mincl = FALSE;
  779.     set_want_col = TRUE;
  780.     if (!repsearch(0)) {
  781.         CLEAROP;
  782.         beep();
  783.     }
  784.     break;
  785.  
  786.       case 'N':
  787.     mtype = MCHAR;
  788.     mincl = FALSE;
  789.     set_want_col = TRUE;
  790.     if (!repsearch(1)) {
  791.         CLEAROP;
  792.         beep();
  793.     }
  794.     break;
  795.  
  796.     /*
  797.      * Character searches 
  798.      */
  799.       case 'T':
  800.     dir = BACKWARD;
  801.     /* FALLTHROUGH */
  802.  
  803.       case 't':
  804.     type = 1;
  805.     goto docsearch;
  806.  
  807.       case 'F':
  808.     dir = BACKWARD;
  809.     /* FALLTHROUGH */
  810.  
  811.       case 'f':
  812. docsearch:
  813.     mtype = MCHAR;
  814.     mincl = TRUE;
  815.     set_want_col = TRUE;
  816.     if ((nchar = vgetc()) == ESC)    /* search char */
  817.         break;
  818.     if (!searchc(nchar, dir, type)) {
  819.         CLEAROP;
  820.         beep();
  821.     }
  822.     break;
  823.  
  824.       case ',':
  825.     flag = 1;
  826.     /* FALLTHROUGH */
  827.  
  828.       case ';':
  829.     mtype = MCHAR;
  830.     mincl = TRUE;
  831.     set_want_col = TRUE;
  832.     if (!crepsearch(flag)) {
  833.         CLEAROP;
  834.         beep();
  835.     }
  836.     break;
  837.  
  838.     /*
  839.      * Function searches 
  840.      */
  841.  
  842.       case '[':
  843.     dir = BACKWARD;
  844.     /* FALLTHROUGH */
  845.  
  846.       case ']':
  847.     mtype = MLINE;
  848.     set_want_col = TRUE;
  849.     if (vgetc() != c) {
  850.         CLEAROP;
  851.         beep();
  852.         break;
  853.     }
  854.     if (!findfunc(dir)) {
  855.         CLEAROP;
  856.         beep();
  857.     }
  858.     break;
  859.  
  860.     /*
  861.      * Marks 
  862.      */
  863.  
  864.       case 'm':
  865.     CLEAROP;
  866.     if (!setmark(vgetc()))
  867.         beep();
  868.     break;
  869.  
  870.       case '\'':
  871.     flag = TRUE;
  872.     /* FALLTHROUGH */
  873.  
  874.       case '`':
  875.     {
  876.         LPtr            mtmp, *mark = getmark(vgetc());
  877.  
  878.         if (mark == NULL) {
  879.         CLEAROP;
  880.         beep();
  881.         } else {
  882.         mtmp = *mark;
  883.         setpcmark();
  884.         *Curschar = mtmp;
  885.         if (flag)
  886.             beginline(TRUE);
  887.         }
  888.         mtype = flag ? MLINE : MCHAR;
  889.         mincl = TRUE;    /* ignored if not MCHAR */
  890.         set_want_col = TRUE;
  891.     }
  892.     break;
  893.  
  894.       case 'r':
  895.     CLEAROP;
  896.     if (lineempty(Curschar)) {    /* Nothing to replace */
  897.         beep();
  898.         break;
  899.     }
  900.     if ((nchar = vgetc()) == ESC)
  901.         break;
  902.  
  903.     Prenum = DEFAULT1(Prenum);
  904.     n = strlen(Curschar->linep->s) - Curschar->index;
  905.     if (n < Prenum) {
  906.         beep();
  907.         break;
  908.     }
  909.     ResetBuffers();
  910.  
  911.     nn = RowNumber(Curschar);
  912.     AppendPositionToUndobuff(Curschar->index, nn);
  913.     AppendPositionToUndoUndobuff(Curschar->index, nn);
  914.  
  915.     while (Prenum > 0) {
  916.         AppendToRedobuff("r");
  917.         AppendToRedobuff(mkstr(nchar));
  918.  
  919.         AppendToUndobuff("r");
  920.         AppendToUndobuff(mkstr(gchar(Curschar)));
  921.  
  922.         AppendToUndoUndobuff("r");
  923.         AppendToUndoUndobuff(mkstr(nchar));
  924.  
  925.         pchar(Curschar, nchar);    /* Change current character. */
  926.  
  927.         if (Prenum > 1) {
  928.         oneright();
  929.         AppendToRedobuff("l");
  930.         AppendToUndobuff("l");
  931.         AppendToUndoUndobuff("l");
  932.         }
  933.         Prenum--;
  934.     }
  935.  
  936.     CHANGED;
  937.     updateline();
  938.     break;
  939.  
  940.       case '~':        /* swap case */
  941.     CLEAROP;
  942.     if (lineempty(Curschar)) {
  943.         beep();
  944.         break;
  945.     }
  946.     ResetBuffers();
  947.  
  948.     n = RowNumber(Curschar);
  949.     AppendPositionToUndobuff(Curschar->index, n);
  950.     AppendPositionToUndoUndobuff(Curschar->index, n);
  951.  
  952.     Prenum = DEFAULT1(Prenum);
  953.     if (Prenum > 0) {
  954.         AppendNumberToRedobuff(Prenum);
  955.         AppendNumberToUndobuff(Prenum);
  956.         AppendNumberToUndoUndobuff(Prenum);
  957.     }
  958.     AppendToRedobuff("~");
  959.     AppendToUndobuff("~");
  960.     AppendToUndoUndobuff("~");
  961.  
  962.     while (Prenum > 0) {
  963.         c = gchar(Curschar);
  964.         if (isalpha(c)) {
  965.         if (islower(c))
  966.             pchar(Curschar, toupper(c));
  967.         else
  968.             pchar(Curschar, tolower(c));
  969.         }
  970.         if (!oneright())
  971.         break;
  972.         Prenum--;
  973.     }
  974.  
  975.     CHANGED;
  976.     updateline();
  977.     break;
  978.  
  979.       case UNDO_SHIFTJ:
  980.     CLEAROP;
  981.     if (UndoInProgress) {
  982.         if (dojoin(FALSE, FALSE))
  983.         updateNextscreen(VALID_TO_CURSCHAR);
  984.         break;
  985.     }
  986.     goto doSHIFTJcommand;
  987.  
  988.       case 'J':
  989.     CLEAROP;
  990. doSHIFTJcommand:
  991.     if (nextline(Curschar) == NULL) {    /* on last line */
  992.         beep();
  993.         break;
  994.     }
  995.     ResetBuffers();
  996.  
  997.     temp_Curschar = *Curschar;
  998.     nn = strlen(Curschar->linep->s);
  999.     if (nn < 0)
  1000.         nn = 0;
  1001.     n = RowNumber(&temp_Curschar);
  1002.  
  1003.     AppendToRedobuff("J");
  1004.  
  1005.     AppendPositionToUndobuff(nn, n);
  1006.  
  1007.     AppendPositionToUndoUndobuff(0, n);
  1008.     AppendToUndoUndobuff("J");
  1009.  
  1010.     if (linewhite(nextline(Curschar))) {
  1011.         AppendToUndobuff("a\n");
  1012.         if (!dojoin(FALSE, TRUE)) {
  1013.         beep();
  1014.         break;
  1015.         }
  1016.     } else if (lineempty(Curschar)) {
  1017.         AppendToUndobuff("i\n");
  1018.         if (!dojoin(FALSE, TRUE)) {
  1019.         beep();
  1020.         break;
  1021.         }
  1022.     } else {
  1023.         AppendToUndobuff("dli\n");
  1024.         if (!dojoin(TRUE, TRUE)) {
  1025.         beep();
  1026.         break;
  1027.         }
  1028.     }
  1029.  
  1030.     AppendToUndobuff(ESC_STR);
  1031.     AppendPositionToUndobuff(nn, n);
  1032.  
  1033.     updateNextscreen(VALID_TO_CURSCHAR);
  1034.     break;
  1035.  
  1036.       case K_CGRAVE:        /* shorthand command */
  1037.     CLEAROP;
  1038.     stuffReadbuff(":e #\n");
  1039.     break;
  1040.  
  1041.       case 'Z':        /* write, if changed, and exit */
  1042.     if (vgetc() != 'Z') {
  1043.         beep();
  1044.         break;
  1045.     }
  1046.     if (Changed) {
  1047.         if (Filename != NULL) {
  1048.         if (!writeit(Filename, (LPtr *) NULL, (LPtr *) NULL))
  1049.             return;
  1050.         } else {
  1051.         emsg("No output file");
  1052.         return;
  1053.         }
  1054.     }
  1055.     getout(0);
  1056.     break;
  1057.  
  1058.       case '.':
  1059.     CLEAROP;
  1060.     if (Redobuffptr != NULL) {
  1061.         stuffReadbuff(Redobuff);
  1062.  
  1063.         stuffReadbuff(ENABLE_REDRAWING_STR);
  1064.         RedrawingDisabled = TRUE;
  1065.     } else
  1066.         beep();
  1067.     break;
  1068.  
  1069.       case 'u':
  1070.       case K_UNDO:
  1071.     CLEAROP;
  1072.     if (UndoInProgress) {
  1073.         p = UndoUndobuff;
  1074.         UndoUndobuff = Undobuff;
  1075.         Undobuff = p;
  1076.         p = UndoUndobuffptr;
  1077.         UndoUndobuffptr = Undobuffptr;
  1078.         Undobuffptr = p;
  1079.  
  1080.         UndoInProgress = FALSE;
  1081.         RedrawingDisabled = FALSE;
  1082.         updateNextscreen(NOT_VALID);
  1083.     } else if (Undobuffptr != NULL) {
  1084.         stuffReadbuff(Undobuff);
  1085.         stuffReadbuff("u");
  1086.         UndoInProgress = TRUE;
  1087.         RedrawingDisabled = TRUE;
  1088.     } else {
  1089.         beep();
  1090.     }
  1091.     break;
  1092.  
  1093.       default:
  1094.     CLEAROP;
  1095.     beep();
  1096.     break;
  1097.     }
  1098.  
  1099.     /*
  1100.      * If an operation is pending, handle it... 
  1101.      */
  1102.     if (finish_op) {        /* we just finished an operator */
  1103.     if (operator == NOP)    /* ... but it was cancelled */
  1104.         return;
  1105.  
  1106.     switch (operator) {
  1107.  
  1108.       case LSHIFT:
  1109.       case RSHIFT:
  1110.         ResetBuffers();
  1111.  
  1112.         n = RowNumber(&startop);
  1113.         AppendPositionToUndobuff(startop.index, n);
  1114.         AppendPositionToUndoUndobuff(startop.index, n);
  1115.         if (Prenum != 0) {
  1116.         AppendNumberToRedobuff(Prenum);
  1117.         AppendNumberToUndobuff(Prenum);
  1118.         AppendNumberToUndoUndobuff(Prenum);
  1119.         }
  1120.         AppendToRedobuff((operator == LSHIFT) ? "<" : ">");
  1121.         AppendToUndobuff((operator == LSHIFT) ? ">" : "<");
  1122.         AppendToUndoUndobuff((operator == LSHIFT) ? "<" : ">");
  1123.         AppendToRedobuff(mkstr(c));
  1124.         if (c == '>')
  1125.         AppendToUndobuff("<");
  1126.         else if (c == '<')
  1127.         AppendToUndobuff(">");
  1128.         else
  1129.         AppendToUndobuff(mkstr(c));
  1130.         AppendToUndoUndobuff(mkstr(c));
  1131.  
  1132.         doshift(operator);
  1133.         break;
  1134.  
  1135.       case DELETE:
  1136.         ResetBuffers();
  1137.  
  1138.         n = RowNumber(&startop);
  1139.         AppendPositionToUndoUndobuff(startop.index, n);
  1140.  
  1141.         temp_Curschar = (lt(&startop, Curschar) ? startop : *Curschar);
  1142.         n = RowNumber(&temp_Curschar);
  1143.         if (Prenum != 0) {
  1144.         AppendNumberToRedobuff(Prenum);
  1145.         AppendNumberToUndoUndobuff(Prenum);
  1146.         }
  1147.         AppendToRedobuff("d");
  1148.         AppendToUndoUndobuff("d");
  1149.         AppendToRedobuff(mkstr(c));
  1150.         AppendToUndoUndobuff(mkstr(c));
  1151.         if (nchar != NUL) {
  1152.         AppendToRedobuff(mkstr(nchar));
  1153.         AppendToUndoUndobuff(mkstr(nchar));
  1154.         }
  1155.         AppendPositionToUndobuff(temp_Curschar.index, n);
  1156.  
  1157.         dodelete(TRUE, !UndoInProgress, !UndoInProgress);
  1158.  
  1159.         AppendPositionToUndobuff(temp_Curschar.index, n);
  1160.         break;
  1161.  
  1162.       case YANK:
  1163.         ResetBuffers();    /* no redo/undo/(undo of undo) on yank... */
  1164.         doyank();
  1165.         if (!ybcrossline)
  1166.         *Curschar = startop;
  1167.         else if (lt(&startop, Curschar))
  1168.         *Curschar = startop;
  1169.         break;
  1170.  
  1171.       case CHANGE:
  1172.         ResetBuffers();
  1173.  
  1174.         n = RowNumber(&startop);
  1175.         AppendPositionToUndoUndobuff(startop.index, n);
  1176.  
  1177.         temp_Curschar = (lt(&startop, Curschar) ? startop : *Curschar);
  1178.         n = RowNumber(&temp_Curschar);
  1179.         if (mtype == MLINE)
  1180.         AppendPositionToUndobuff(0, n);
  1181.         else
  1182.         AppendPositionToUndobuff(temp_Curschar.index, n);
  1183.  
  1184.         if (Prenum != 0) {
  1185.         AppendNumberToRedobuff(Prenum);
  1186.         AppendNumberToUndoUndobuff(Prenum);
  1187.         }
  1188.         AppendToRedobuff("c");
  1189.         AppendToUndoUndobuff("c");
  1190.         AppendToRedobuff(mkstr(c));
  1191.         AppendToUndoUndobuff(mkstr(c));
  1192.         if (nchar != NUL) {
  1193.         AppendToRedobuff(mkstr(nchar));
  1194.         AppendToUndoUndobuff(mkstr(nchar));
  1195.         }
  1196.         dochange();
  1197.  
  1198.         last_command = 'c';
  1199.         break;
  1200.  
  1201.       default:
  1202.         beep();
  1203.     }
  1204.     operator = NOP;
  1205.     }
  1206. }
  1207.  
  1208. /*
  1209.  * tabinout(shift_type, num) 
  1210.  *
  1211.  * If shift_type == RSHIFT, add a tab to the begining of the next num lines;
  1212.  * otherwise delete a tab from the beginning of the next num lines. 
  1213.  */
  1214. static void
  1215. tabinout(shift_type, num)
  1216.     int             shift_type;
  1217.     int             num;
  1218. {
  1219.     LPtr           *p;
  1220.  
  1221.     beginline(FALSE);
  1222.     while (num-- > 0) {
  1223.     beginline(FALSE);
  1224.     if (shift_type == RSHIFT)
  1225.         inschar(TAB);
  1226.     else {
  1227.         if (gchar(Curschar) == TAB)
  1228.         delchar(TRUE, FALSE);
  1229.     }
  1230.     if (num > 0) {
  1231.         if ((p = nextline(Curschar)) != NULL)
  1232.         *Curschar = *p;
  1233.         else
  1234.         break;
  1235.     }
  1236.     }
  1237. }
  1238.  
  1239. /*
  1240.  * doshift - handle a shift operation 
  1241.  */
  1242. static void
  1243. doshift(op)
  1244.     int             op;
  1245. {
  1246.     LPtr            top, bot;
  1247.     int             nlines;
  1248.  
  1249.     top = startop;
  1250.     bot = *Curschar;
  1251.  
  1252.     if (lt(&bot, &top))
  1253.     pswap(top, bot);
  1254.  
  1255.     nlines = cntllines(&top, &bot);
  1256.     *Curschar = top;
  1257.     tabinout(op, nlines);
  1258.  
  1259.     /*
  1260.      * The cursor position afterward is the prior of the two positions. 
  1261.      */
  1262.     *Curschar = top;
  1263.  
  1264.     /*
  1265.      * If we were on the last char of a line that got shifted left, then move
  1266.      * left one so we aren't beyond the end of the line 
  1267.      */
  1268.     if (gchar(Curschar) == NUL && Curschar->index > 0)
  1269.     Curschar->index--;
  1270.  
  1271.     if (op == RSHIFT)
  1272.     oneright();
  1273.     else
  1274.     oneleft();
  1275.  
  1276.     updateNextscreen(NOT_VALID);
  1277.  
  1278.     if (nlines > P(P_RP))
  1279.     smsg("%d lines %ced", nlines, (op == RSHIFT) ? '>' : '<');
  1280. }
  1281.  
  1282. /*
  1283.  * dodelete - handle a delete operation 
  1284.  */
  1285. static void
  1286. dodelete(redraw, setup_for_undo, try_to_yank)
  1287.     bool_t          redraw;
  1288.     bool_t          setup_for_undo;
  1289.     bool_t          try_to_yank;
  1290. {
  1291.     LPtr            top, bot;
  1292.     int             nlines;
  1293.     int             n;
  1294.  
  1295.     /*
  1296.      * Do a yank of whatever we're about to delete. If there's too much stuff
  1297.      * to fit in the yank buffer, then get a confirmation before doing the
  1298.      * delete. This is crude, but simple. And it avoids doing a delete of
  1299.      * something we can't put back if we want. 
  1300.      */
  1301.     if (try_to_yank) {
  1302.     if (!doyank()) {
  1303.         msg("yank buffer exceeded: press <y> to confirm");
  1304.         if (vgetc() != 'y') {
  1305.         emsg("delete aborted");
  1306.         *Curschar = startop;
  1307.         return;
  1308.         }
  1309.     }
  1310.     }
  1311.     top = startop;
  1312.     bot = *Curschar;
  1313.  
  1314.     if (lt(&bot, &top))
  1315.     pswap(top, bot);
  1316.  
  1317.     *Curschar = top;
  1318.     nlines = cntllines(&top, &bot);
  1319.     cursupdate();
  1320.  
  1321.     if (mtype == MLINE) {
  1322.     if (operator == CHANGE) {
  1323.         last_command_char = 'a';
  1324.         delline(nlines - 1, TRUE);
  1325.         Curschar->index = 0;
  1326.         while (delchar(TRUE, FALSE));
  1327.     } else {
  1328.         if ((Filetop->linep->next == top.linep) &&
  1329.         (bot.linep->next == Fileend->linep))
  1330.         last_command_char = 'a';
  1331.         else if (bot.linep->next == Fileend->linep)
  1332.         last_command_char = 'o';
  1333.         else
  1334.         last_command_char = 'O';
  1335.         if (setup_for_undo)
  1336.         AppendToUndobuff(mkstr(last_command_char));
  1337.         delline(nlines, TRUE);
  1338.     }
  1339.     } else if (top.linep == bot.linep) {    /* del. within line */
  1340.     if (!mincl)
  1341.         dec(&bot);
  1342.  
  1343.     if (endofline(&bot))
  1344.         last_command_char = 'a';
  1345.     else
  1346.         last_command_char = 'i';
  1347.     if (setup_for_undo)
  1348.         AppendToUndobuff(mkstr(last_command_char));
  1349.     n = bot.index - top.index + 1;
  1350.     while (n--)
  1351.         if (!delchar(TRUE, FALSE))
  1352.         break;
  1353.     } else {            /* del. between lines */
  1354.     if (endofline(&top)) {
  1355.         if (nextline(&top)) {
  1356.         if (lineempty(nextline(&top)))
  1357.             last_command_char = 'a';
  1358.         else
  1359.             last_command_char = 'i';
  1360.         } else {
  1361.         last_command_char = 'a';
  1362.         }
  1363.     } else {
  1364.         last_command_char = 'i';
  1365.     }
  1366.     if (setup_for_undo)
  1367.         AppendToUndobuff(mkstr(last_command_char));
  1368.  
  1369.     n = Curschar->index;
  1370.     while (Curschar->index >= n)
  1371.         if (!delchar(TRUE, FALSE))
  1372.         break;
  1373.  
  1374.     top = *Curschar;
  1375.     *Curschar = *nextline(Curschar);
  1376.     delline(nlines - 2, TRUE);
  1377.     Curschar->index = 0;
  1378.     n = bot.index;
  1379.     if (!mincl)
  1380.         n--;
  1381.  
  1382.     while (n-- >= 0)
  1383.         if (!delchar(TRUE, FALSE))
  1384.         break;
  1385.     *Curschar = top;
  1386.     dojoin(FALSE, FALSE);
  1387.     }
  1388.  
  1389.     if (mtype == MCHAR && nlines == 1 && redraw && P(P_NU) == FALSE)
  1390.     updateline();
  1391.     else
  1392.     updateNextscreen(NOT_VALID);
  1393.  
  1394.     if (nlines > P(P_RP))
  1395.     smsg("%d fewer lines", nlines);
  1396.  
  1397.     if (setup_for_undo) {
  1398.     AppendToUndobuff(Yankbuff);
  1399.     AppendToUndobuff(ESC_STR);
  1400.     }
  1401. }
  1402.  
  1403. /*
  1404.  * dochange - handle a change operation 
  1405.  */
  1406. static void
  1407. dochange()
  1408. {
  1409.     LPtr            l;
  1410.  
  1411.     if (lt(Curschar, &startop))
  1412.     l = *Curschar;
  1413.     else
  1414.     l = startop;
  1415.  
  1416.     dodelete(FALSE, FALSE, !UndoInProgress);
  1417.  
  1418.     if ((l.index > Curschar->index) && !lineempty(Curschar))
  1419.     inc(Curschar);
  1420.  
  1421.     startinsert(FALSE);
  1422. }
  1423.  
  1424. static          bool_t
  1425. doyank()
  1426. {
  1427.     LPtr            top, bot;
  1428.     char           *ybend = &Yankbuff[YANKSIZE - 1];
  1429.     int             nlines;
  1430.  
  1431.     Yankbuffptr = Yankbuff;
  1432.  
  1433.     top = startop;
  1434.     bot = *Curschar;
  1435.  
  1436.     if (lt(&bot, &top))
  1437.     pswap(top, bot);
  1438.  
  1439.     nlines = cntllines(&top, &bot);
  1440.  
  1441.     ybtype = mtype;        /* set the yank buffer type */
  1442.     ybcrossline = FALSE;
  1443.     if (LINEOF(&top) != LINEOF(&bot))
  1444.     ybcrossline = TRUE;
  1445.  
  1446.     if (mtype == MLINE) {
  1447.     ybcrossline = TRUE;
  1448.     top.index = 0;
  1449.     bot.index = strlen(bot.linep->s);
  1450.     /*
  1451.      * The following statement checks for the special case of yanking a
  1452.      * blank line at the beginning of the file. If not handled right, we
  1453.      * yank an extra char (a newline). 
  1454.      */
  1455.     if (dec(&bot) == -1) {
  1456.         *Yankbuff = NUL;
  1457.         Yankbuffptr = NULL;
  1458.         return TRUE;
  1459.     }
  1460.     } else {
  1461.     if (!mincl)
  1462.         if (!equal(&top, &bot))
  1463.         dec(&bot);
  1464.     }
  1465.  
  1466.     for (; ltoreq(&top, &bot); inc(&top)) {
  1467.     *Yankbuffptr = (gchar(&top) != NUL) ? gchar(&top) : NL;
  1468.     Yankbuffptr++;
  1469.     if (Yankbuffptr >= ybend) {
  1470.         *Yankbuffptr = NUL;
  1471.         msg("yank too big for buffer");
  1472.         ybtype = MBAD;
  1473.         return FALSE;
  1474.     }
  1475.     }
  1476.  
  1477.     *Yankbuffptr = NUL;
  1478.  
  1479.     if (operator == YANK)
  1480.     if (nlines > P(P_RP))
  1481.         smsg("%d lines yanked", nlines);
  1482.  
  1483.     return TRUE;
  1484. }
  1485.  
  1486. static void
  1487. doput(dir)
  1488.     int             dir;
  1489. {
  1490.     bool_t          type;
  1491.  
  1492.     if (ybtype == MBAD) {
  1493.     beep();
  1494.     return;
  1495.     }
  1496.     type = (ybtype == MCHAR);
  1497.     if (dir == FORWARD)
  1498.     stuffReadbuff(type ? "a" : "o");
  1499.     else
  1500.     stuffReadbuff(type ? "i" : "O");
  1501.  
  1502.     stuffReadbuff(Yankbuff);
  1503.     stuffReadbuff(ESC_STR);
  1504.  
  1505.     if (ybtype != MCHAR)
  1506.     stuffReadbuff("^");
  1507. }
  1508.  
  1509. static void
  1510. startinsert(startln)
  1511.     int             startln;    /* if set, insert at start of line */
  1512. {
  1513.     *Insstart = *Curschar;
  1514.     if (startln) {
  1515.     Insstart->index = 0;
  1516.     }
  1517.     *Insbuff = NUL;
  1518.     Insbuffptr = NULL;
  1519.  
  1520.     State = INSERT;
  1521.     if (P(P_MO))
  1522.     msg("Insert Mode");
  1523. }
  1524.  
  1525. void
  1526. ResetBuffers()
  1527. {
  1528.     if (UndoInProgress)
  1529.     return;
  1530.  
  1531.     *Redobuff = NUL;
  1532.     Redobuffptr = NULL;
  1533.  
  1534.     *Undobuff = NUL;
  1535.     Undobuffptr = NULL;
  1536.  
  1537.     *UndoUndobuff = NUL;
  1538.     UndoUndobuffptr = NULL;
  1539. }
  1540.  
  1541. void
  1542. AppendToInsbuff(s)
  1543.     char           *s;
  1544. {
  1545.     if (UndoInProgress)
  1546.     return;
  1547.  
  1548.     if (Insbuffptr == NULL) {
  1549.     if ((strlen(s) + 1) < INSERT_SIZE) {
  1550.         strcpy(Insbuff, s);
  1551.         Insbuffptr = Insbuff;
  1552.         return;
  1553.     }
  1554.     } else if ((strlen(Insbuff) + strlen(s) + 1) < INSERT_SIZE) {
  1555.     strcat(Insbuff, s);
  1556.     return;
  1557.     }
  1558.     emsg("Couldn't AppendToInsbuff() - clearing Insbuff\n");
  1559.     *Insbuff = NUL;
  1560.     Insbuffptr = NULL;
  1561. }
  1562.  
  1563. void
  1564. AppendToRedobuff(s)
  1565.     char           *s;
  1566. {
  1567.     if (UndoInProgress)
  1568.     return;
  1569.  
  1570.     if (Redobuffptr == (char *) (-2)) {
  1571.     return;
  1572.     }
  1573.     if (Redobuffptr == (char *) (-1)) {
  1574.         Redobuffptr = (char *) (-2);
  1575.     emsg("Couldn't AppendToRedobuff() - Redobuff corrupt");
  1576.     return;
  1577.     }
  1578.     if (Redobuffptr == NULL) {
  1579.     if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  1580.         strcpy(Redobuff, s);
  1581.         Redobuffptr = Redobuff;
  1582.         return;
  1583.     }
  1584.     } else if ((strlen(Redobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  1585.     strcat(Redobuff, s);
  1586.     return;
  1587.     }
  1588.     emsg("Couldn't AppendToRedobuff() - clearing Redobuff");
  1589.     *Redobuff = NUL;
  1590.     Redobuffptr = (char *) (-1);
  1591. }
  1592.  
  1593. void
  1594. AppendNumberToRedobuff(n)
  1595.     int             n;
  1596. {
  1597.     char            buf[32];
  1598.  
  1599.     if (UndoInProgress)
  1600.     return;
  1601.  
  1602.     sprintf(buf, "%d", n);
  1603.     AppendToRedobuff(buf);
  1604. }
  1605.  
  1606. void
  1607. AppendToUndobuff(s)
  1608.     char           *s;
  1609. {
  1610.     if (UndoInProgress)
  1611.     return;
  1612.  
  1613.     if (Undobuffptr == (char *) (-2)) {
  1614.     return;
  1615.     }
  1616.     if (Undobuffptr == (char *) (-1)) {
  1617.         Undobuffptr = (char *) (-2);
  1618.     emsg("Couldn't AppendToUndobuff() - Undobuff corrupt");
  1619.     return;
  1620.     }
  1621.     if (Undobuffptr == NULL) {
  1622.     if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  1623.         strcpy(Undobuff, s);
  1624.         Undobuffptr = Undobuff;
  1625.         return;
  1626.     }
  1627.     } else if ((strlen(Undobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  1628.     strcat(Undobuff, s);
  1629.     return;
  1630.     }
  1631.     emsg("Couldn't AppendToUndobuff() - clearing Undobuff");
  1632.     *Undobuff = NUL;
  1633.     Undobuffptr = (char *) (-1);
  1634. }
  1635.  
  1636. void
  1637. AppendNumberToUndobuff(n)
  1638.     int             n;
  1639. {
  1640.     char            buf[32];
  1641.  
  1642.     if (UndoInProgress)
  1643.     return;
  1644.  
  1645.     sprintf(buf, "%d", n);
  1646.     AppendToUndobuff(buf);
  1647. }
  1648.  
  1649. void
  1650. AppendPositionToUndobuff(column, row)
  1651.     int             column;
  1652.     int             row;
  1653. {
  1654.     if (UndoInProgress)
  1655.     return;
  1656.  
  1657.     AppendNumberToUndobuff(row);
  1658.     AppendToUndobuff("G");
  1659.     AppendNumberToUndobuff(column);
  1660.     if (column)
  1661.     AppendToUndobuff("l");
  1662. }
  1663.  
  1664. void
  1665. AppendToUndoUndobuff(s)
  1666.     char           *s;
  1667. {
  1668.     if (UndoInProgress)
  1669.     return;
  1670.  
  1671.     if (UndoUndobuffptr == (char *) (-2)) {
  1672.     return;
  1673.     }
  1674.     if (UndoUndobuffptr == (char *) (-1)) {
  1675.         UndoUndobuffptr = (char *) (-2);
  1676.     emsg("Couldn't AppendToUndoUndobuff() - UndoUndobuff corrupt");
  1677.     return;
  1678.     }
  1679.     if (UndoUndobuffptr == NULL) {
  1680.     if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  1681.         strcpy(UndoUndobuff, s);
  1682.         UndoUndobuffptr = Undobuff;
  1683.         return;
  1684.     }
  1685.     } else if ((strlen(UndoUndobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  1686.     strcat(UndoUndobuff, s);
  1687.     return;
  1688.     }
  1689.     emsg("Couldn't AppendToUndoUndobuff() - clearing UndoUndobuff");
  1690.     *UndoUndobuff = NUL;
  1691.     UndoUndobuffptr = (char *) (-1);
  1692. }
  1693.  
  1694. void
  1695. AppendNumberToUndoUndobuff(n)
  1696.     int             n;
  1697. {
  1698.     char            buf[32];
  1699.  
  1700.     if (UndoInProgress)
  1701.     return;
  1702.  
  1703.     sprintf(buf, "%d", n);
  1704.     AppendToUndoUndobuff(buf);
  1705. }
  1706.  
  1707. void
  1708. AppendPositionToUndoUndobuff(column, row)
  1709.     int             column;
  1710.     int             row;
  1711. {
  1712.     if (UndoInProgress)
  1713.     return;
  1714.  
  1715.     AppendNumberToUndoUndobuff(row);
  1716.     AppendToUndoUndobuff("G");
  1717.     AppendNumberToUndoUndobuff(column);
  1718.     if (column)
  1719.     AppendToUndoUndobuff("l");
  1720. }
  1721.  
  1722. static          bool_t
  1723. dojoin(leading_space, strip_leading_spaces)
  1724.     bool_t          leading_space;
  1725.     bool_t          strip_leading_spaces;
  1726. {
  1727.     int             scol;    /* save cursor column */
  1728.     int             currsize;    /* size of the current line */
  1729.     int             nextsize;    /* size of the next line */
  1730.  
  1731.     if (nextline(Curschar) == NULL)    /* on last line */
  1732.     return FALSE;
  1733.  
  1734.     if (!canincrease(nextsize = strlen(Curschar->linep->next->s)))
  1735.     return FALSE;
  1736.  
  1737.     currsize = strlen(Curschar->linep->s);
  1738.  
  1739.     while (oneright());        /* to end of line */
  1740.  
  1741.     strcat(Curschar->linep->s, Curschar->linep->next->s);
  1742.  
  1743.     /*
  1744.      * Delete the following line. To do this we move the cursor there
  1745.      * briefly, and then move it back. Don't back up if the delete made us
  1746.      * the last line. 
  1747.      */
  1748.     Curschar->linep = Curschar->linep->next;
  1749.     scol = Curschar->index;
  1750.  
  1751.     if (nextline(Curschar) != NULL) {
  1752.     delline(1, TRUE);
  1753.     Curschar->linep = Curschar->linep->prev;
  1754.     } else
  1755.     delline(1, TRUE);
  1756.  
  1757.     Curschar->index = scol;
  1758.  
  1759.     if (currsize)
  1760.     oneright();        /* go to first char. of joined line */
  1761.  
  1762.     if (nextsize != 0 && strip_leading_spaces) {
  1763.     /*
  1764.      * Delete leading white space on the joined line and insert a single
  1765.      * space. 
  1766.      */
  1767.     while (gchar(Curschar) == ' ' || gchar(Curschar) == TAB) {
  1768.         delchar(TRUE, TRUE);
  1769.     }
  1770.     if (leading_space)
  1771.         inschar(' ');
  1772.     }
  1773.     CHANGED;
  1774.  
  1775.     return TRUE;
  1776. }
  1777.  
  1778. /*
  1779.  * linewhite() - returns TRUE if the line consists only of white space
  1780.  */
  1781.  
  1782. bool_t
  1783. linewhite(p)
  1784.     LPtr           *p;
  1785. {
  1786.     register int    i;
  1787.     register char   c;
  1788.  
  1789.     i = 1;
  1790.     c = p->linep->s[0];
  1791.     while (c != NUL) {
  1792.     if (c != ' ' && c != '\t')
  1793.         return (FALSE);
  1794.     c = p->linep->s[i++];
  1795.     }
  1796.  
  1797.     return (TRUE);
  1798. }
  1799. SHAR_EOF
  1800. #    End of shell archive
  1801. exit 0
  1802. -- 
  1803. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1804. Have five nice days.
  1805.